#include <surface\terrainRowsBin.h>
#include <base\global.h>
#include <model.h>
#include <geo\inverseMercatorProjection.h>
#include <modules\fileTerrainModule.h>

#include <iomanip>

terrainRowsBin::terrainRowsBin(int rows_count_, int row_length_, Poco::Path dir_, fileTerrainModule *terrain_module_) {
  rows_count = rows_count_;
  row_length = row_length_;
  dir = dir_;
  terrain_module = terrain_module_;

  textures_dir = dir;
  textures_dir.popDirectory();
  textures_dir.pushDirectory(TEXTURE_DIR_BASE_NAME);

  rows = new vec3d *[rows_count];

  for (int row = 0; row != rows_count; row++) {
    rows[row] = new vec3d[row_length];
  }

  initial_state = true;
}

terrainRowsBin::~terrainRowsBin() {
}

void
terrainRowsBin::insertPoint(int row_index, int index_in_row, vec3d point) {

  rows[foo.size()][index_in_row] = point;
  if (index_in_row == row_length - 1) foo.push(row_index);
  
  if (foo.size() > 3 && index_in_row == row_length - 1) {

    interpolate();

    // rotate rows
    vec3d *tmp = rows[0];
    rows[0] = rows[1];
    rows[1] = rows[2];
    rows[2] = rows[3];       
    rows[3] = tmp;

    if (foo.size() > 3) foo.pop();
  }
}

void
terrainRowsBin::interpolate() {

  vec2i size = vec2i(INTERPOLATED_TERRAIN_TILE_SIZE, INTERPOLATED_TERRAIN_TILE_SIZE);

  for (int roffset = 0; roffset != row_length - 4; roffset++) {
  //for (int roffset = 0; roffset != 36; roffset++) {

    for (int ritem = 0; ritem != 4; ritem++) {
      for (int row_index = 0; row_index!= 4; row_index++) {
        surface.addControlHeight(row_index, ritem, rows[row_index][roffset + ritem][2]);
      }
    }

    vec2i res(abs(ROUND(rows[2][roffset + 2][0] - rows[1][roffset + 1][0])),
              abs(ROUND(rows[2][roffset + 2][1] - rows[1][roffset + 1][1])));



    surface.computeSurface(res);

    // add interpolated values to points bins
    double **heights = surface.getCoonsHeights();

    vec2i from(rows[1][roffset + 1][0], rows[1][roffset + 1][1]); // x (row_index)
    vec2i to  (rows[2][roffset + 2][0], rows[2][roffset + 2][1]); // y (index to row)
    vec2i sign(1, 1);

    if (from[0] > to[0]) sign.x = -1;
    if (from[1] > to[1]) sign.y = -1;

    pointsBin *pbin;

    for (int iri = from[0]; iri != to[0]; iri +=sign[0]) { // x (89...)

      iri_iter = pbins.find(iri / size[0]); // row

      if (iri_iter == pbins.end()) {
        pbins[iri / size[0]];//[iir / size[1]] = pbin;
        iri_iter = pbins.find(iri / size[0]);
      }

      for (int iir = from[1]; iir != to[1]; iir += sign[1]) { // y(57...)

        iir_iter = iri_iter->second.find(iir / size[1]);
        if (iir_iter == iri_iter->second.end()) {
          pbin = new pointsBin(vec2i(iri / size[0], iir / size[1]), size);
          iri_iter->second[iir / size[1]] = pbin;
          
          pbin->addHeight(iri, iir, heights[abs(iri - from[0])][abs(iir - from[1])]);
        }
        else {
          if (iir_iter->second->addHeight(iri, iir, heights[abs(iri - from[0])][abs(iir - from[1])])) {

            // check if appropriate texture exists
            stringstream str; 
            str << terrain_module->levels_interval[0] + terrain_module->level0_offset;
            dir.pushDirectory(str.str());
            textures_dir.pushDirectory(str.str());

            int col_prefix = iri / (size[0] * 1024);
            int col_index  = (iri / size[0]) % 1024;

            int row_prefix = iir / (size[1] * 1024);
            int row_index  = (iir / size[1]) % 1024;

            str.str("");
            str << col_prefix;
            dir.pushDirectory(str.str());
            textures_dir.pushDirectory(str.str());

            str.str("");
            str << col_index;
            dir.pushDirectory(str.str());
            textures_dir.pushDirectory(str.str());

            str.str("");
            str << row_prefix;
            dir.pushDirectory(str.str());
            textures_dir.pushDirectory(str.str());

            str.str("");
            str << row_index << ".png";
            Poco::File file(Poco::Path(textures_dir.absolute().toString(), str.str()));
            if (file.exists()) {
              Poco::File destination_final(dir);
              destination_final.createDirectories();
              str.str("");
              str << row_index << ".png";
              //std::cout << str << endl;
              Poco::File hmap(Poco::Path(dir.absolute().toString(), str.str()));
              iir_iter->second->save(hmap.path());
            }
            dir.popDirectory();
            dir.popDirectory();
            dir.popDirectory();
            dir.popDirectory();
            textures_dir.popDirectory();
            textures_dir.popDirectory();
            textures_dir.popDirectory();
            textures_dir.popDirectory();

            delete iir_iter->second;
            iri_iter->second.erase(iir_iter);
          }
        }

        //if (iri / 32 == 281077 && iir / 32 == 180050) {
        /*std::cout << setiosflags (ios::fixed) 
                  << iri << " "
                  << iir << " " 
                  << iri % size[0] << " "
                  << iir % size[1] << " " 
                  << heights[abs(iri - from[0])][abs(iir - from[1])] << endl;
         */
        //}
      }

      //std::cout << std::endl;
    }
    //std::cout << std::endl;
    //std::cout << std::endl;
    //std::cout << std::endl;
  }
}